On this page

Skip to content

A Brief Discussion on Flag Enum Applications and Insights

TLDR

  • Flag Enums use the [Flags] attribute and bitwise operations to effectively manage combinations of multiple states.
  • When defining, use powers of 2 (e.g., 1 << 0, 1 << 1) to ensure flags are independent.
  • It is recommended to use the HasFlag method for state checking to improve code readability.
  • Avoid using the NOT (~) operator to define composite enum items to prevent unexpected numerical results.
  • It is recommended to use plural names for Flag Enum types (e.g., Permissions) and singular names for standard Enums (e.g., DayOfWeek).
  • If an Enum is likely to be extended, define it carefully and be cautious when using All type composite values.

Definition and Design Guidelines for Flag Enums

When to encounter this issue: When you need to define a set of enums that support multiple state combinations, and you want the code to have high readability and extensibility.

Flag Enums are marked with the [Flags] attribute and use bitwise operations to combine multiple states. When defining, each flag must be a power of 2 to ensure that each bit is independent.

csharp
[Flags]
enum Permissions {
    None = 0,
    CanQuery = 1 << 0,  // 1
    CanCreate = 1 << 1, // 2
    CanUpdate = 1 << 2, // 4
    CanDelete = 1 << 3  // 8
}

Naming and Maintenance Suggestions

  • Naming Convention: Microsoft recommends using plural names for Flag Enums (e.g., Permissions) and singular names for standard Enums (e.g., DayOfWeek).
  • Extensibility Considerations: If an All composite value is defined, it must be updated whenever new enum items are added in the future; otherwise, it will lead to logic errors.
  • Avoid using NOT (~): Using ~ to define composite values often causes ToString() to output a numerical value instead of the name, and it can easily lead to logical deviations when checking for inclusion; it should be avoided whenever possible.

Operations and Judgments of Flag Enums

When to encounter this issue: When you need to perform union, intersection, or complement operations on multiple states, or check if a specific state exists within a combination.

Bitwise Operation Applications

  • OR (|): Used to merge states (union).
  • AND (&): Used to filter states (intersection).
  • XOR (^): Used to toggle states (symmetric difference).
  • NOT (~): Used to exclude states (complement).

To remove a specific item from a combination, it is recommended to use the following approach:

csharp
// Remove CanCreate
Permissions result = Permissions.CanUpsert & ~Permissions.CanCreate;

State Checking

To determine if a specific flag is included, it is recommended to prioritize the .HasFlag() method, as its semantics are clearer than manual bitwise operations.

csharp
// Use HasFlag to check
bool hasCreate = Permissions.CanUpsert.HasFlag(Permissions.CanCreate);

// Traditional bitwise operation check
bool hasCreate = (Permissions.CanUpsert & Permissions.CanCreate) == Permissions.CanCreate;

Regarding the check for None

Even if None = 0 is defined, using HasFlag(Permissions.None) will always return true, because an empty set is logically considered a subset of any set.

Change Log

  • 2023-12-05 Initial document creation.